using Sage.CloudStorage.Qiniu.Auth;
using Sage.CloudStorage.Qiniu.Models;
using Sage.Http.Core;

namespace Sage.CloudStorage.Qiniu.Storage
{
    /// <summary>
    /// 下载管理器 - 提供文件下载相关功能
    /// </summary>
    /// <remarks>
    /// 创建下载管理器实例
    /// </remarks>
    /// <param name="httpManager">HTTP请求管理器</param>
    /// <param name="key">七牛云密钥信息</param>
    public class DownloadManager(HttpRequestManager httpManager, QiniuKey key)
    {
        private readonly HttpRequestManager _httpManager = httpManager ?? throw new ArgumentNullException(nameof(httpManager));
        private readonly QiniuKey _key = key ?? throw new ArgumentNullException(nameof(key));

        /// <summary>
        /// 创建私有资源下载URL
        /// </summary>
        /// <param name="url">原始URL</param>
        /// <param name="expireSeconds">过期时间（秒）</param>
        /// <returns>带有下载凭证的URL</returns>
        public string CreatePrivateUrl(string url, int expireSeconds = 3600)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));

            if (expireSeconds <= 0)
                throw new ArgumentException("过期时间必须大于0", nameof(expireSeconds));

            // 创建下载凭证
            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.Download);
            var deadline = DateTimeOffset.UtcNow.AddSeconds(expireSeconds).ToUnixTimeSeconds();
            var token = authProvider.CreateDownloadToken(url, deadline);

            // 构建带凭证的URL
            char separator = url.Contains('?') ? '&' : '?';
            return $"{url}{separator}e={deadline}&token={token}";
        }

        /// <summary>
        /// 下载文件到流
        /// </summary>
        /// <param name="url">下载URL</param>
        /// <param name="outputStream">输出流</param>
        /// <param name="isPrivate">是否为私有资源</param>
        /// <param name="progress">下载进度回调（可选）</param>
        /// <param name="cancellationToken">取消令牌（可选）</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> DownloadToStreamAsync(
            string url,
            Stream outputStream,
            bool isPrivate = false,
            IProgress<float>? progress = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));

            ArgumentNullException.ThrowIfNull(outputStream);

            if (!outputStream.CanWrite)
                throw new ArgumentException("输出流必须可写", nameof(outputStream));

            // 如果是私有资源，则生成带凭证的URL
            if (isPrivate)
            {
                url = CreatePrivateUrl(url);
            }

            // 发送下载请求
            var request = _httpManager.CreateRequest(HttpMethod.Get, url);

            // 添加进度回调（如果提供）
            if (progress != null)
            {
                request = request.WithProgress(progress);
            }

            var response = await request.SendAsync(cancellationToken);

            if (!response.IsSuccessStatusCode)
                return false;

            // 将响应内容写入输出流
            await response.Content.CopyToAsync(outputStream, cancellationToken);
            return true;
        }

        /// <summary>
        /// 下载文件到本地
        /// </summary>
        /// <param name="url">下载URL</param>
        /// <param name="localPath">本地文件路径</param>
        /// <param name="isPrivate">是否为私有资源</param>
        /// <param name="progress">下载进度回调（可选）</param>
        /// <param name="cancellationToken">取消令牌（可选）</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> DownloadToFileAsync(
            string url,
            string localPath,
            bool isPrivate = false,
            IProgress<float>? progress = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(localPath))
                throw new ArgumentNullException(nameof(localPath));

            // 确保目录存在
            string? directory = Path.GetDirectoryName(localPath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            // 下载到文件
            using var fileStream = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None);
            return await DownloadToStreamAsync(url, fileStream, isPrivate, progress, cancellationToken);
        }

        /// <summary>
        /// 下载文件到字节数组
        /// </summary>
        /// <param name="url">下载URL</param>
        /// <param name="isPrivate">是否为私有资源</param>
        /// <param name="progress">下载进度回调（可选）</param>
        /// <param name="cancellationToken">取消令牌（可选）</param>
        /// <returns>文件字节数组</returns>
        public async Task<byte[]?> DownloadToByteArrayAsync(
            string url,
            bool isPrivate = false,
            IProgress<float>? progress = null,
            CancellationToken cancellationToken = default)
        {
            using var memoryStream = new MemoryStream();
            bool success = await DownloadToStreamAsync(url, memoryStream, isPrivate, progress, cancellationToken);

            if (!success)
                return null;

            return memoryStream.ToArray();
        }
    }
}